const PENDING = 'pending' // 等待状态 初始状态
const FULFILLED = 'fulfilled' // 成功状态
const REJECTED = 'rejected' // 失败状态

class MyPromise {

  status = PENDING // 初始状态

  $value = undefined // 成功之后的值
  $reason = undefined // 失败之后的值
  successCallback = [] // 成功回调函数
  failCallback = [] // 失败回调函数


  constructor(execoter) {
    // 错误捕捉
    try {
      execoter(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
    
  }

  resolve = value => { 
    if(this.status !== PENDING) {return} // 如果状态不是初始状态 等待中 那么不进行操作
    this.status = FULFILLED // 状态更改为成功
    this.$value = value // 保存成功后的值
    while(this.successCallback.length) this.successCallback.shift()() // 如果成功回调存在 那么就进行调用
  }
  reject = reason => { 
    if(this.status !== PENDING) {return} // 如果状态不是初始状态 等待中 那么不进行操作
    this.status = REJECTED // 状态更改为失败
    this.$reason = reason // 保存失败后的原因
    while(this.failCallback.length) this.failCallback.shift()() // 如果失败回调存在 那么就进行调用
  }

  then(successCallback, failCallback) { // 返回 MyPromise
    successCallback ? successCallback : value => value // 这里相当于 返回了函数 上一个参数
    failCallback ? failCallback : reason => reason
    let promise2 = new MyPromise((resolve, reject) => { 
      if (this.status === FULFILLED) {
        setTimeout(() => { // 异步 方便获得 promise2 因为是在内部 
          try { // 错误捕捉
             let s = successCallback(this.$value)
            resolvePromise(promise2 ,s, resolve, reject) 
          } catch (error) {
            reject(error)
          }
        }, 0)
      } else if (this.status === REJECTED) {
        setTimeout(() => { // 异步 方便获得 promise2 因为是在内部 
          try { // 错误捕捉
             let s = failCallback(this.$reason)
            resolvePromise(promise2 ,s, resolve, reject) 
          } catch (error) {
            reject(error)
          }
        }, 0)
      } else { 
        // 等待
        // 将成功回调和失败回调存起来
        this.successCallback.push(() => { 
          setTimeout(() => { // 异步 方便获得 promise2 因为是在内部 
          try { // 错误捕捉
             let s = successCallback(this.$value)
            resolvePromise(promise2 ,s, resolve, reject) 
          } catch (error) {
            reject(error)
          }
        }, 0)
        })

        this.failCallback.push(() => { 
          setTimeout(() => { // 异步 方便获得 promise2 因为是在内部 
          try { // 错误捕捉
             let s = failCallback(this.$reason)
            resolvePromise(promise2 ,s, resolve, reject) 
          } catch (error) {
            reject(error)
          }
        }, 0)
        })

      }
    })
    return promise2
  }

  static all(array) { 
    let result = []
    let index = 0

    return new MyPromise((resolve, reject) => { 
      function addData(key, val) { 
        result[key] = val
        index++
        if (index === array.length) { 
          resolve(result)
        }
      }
      for (let i = 0; i < array.length; i++) { 
        let current = array[i];
        if (current instanceof MyPromise) { // promise 对象
          current.then(val => addData(i, val), reject)
        } else { // 普通值
          addData(i, current)
        }
      }
    })
  }

  static resolve(val) { 
    if (val instanceof MyPromise) { 
      return val
    }
    return new MyPromise(resolve => resolve(val))
  }

}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) { // 判断 返回的值是否就是当前值
    return reject(new TypeError('chaining cycle detected for promise #<MyPromise>')) // 返回类型错误
  }
  if (x instanceof MyPromise) { // 判断是否是 MyPromise 是 就给对应事件传递对应参数
    // x.then(value => resolve(value), reason => reject(reason))
    x.then(resolve, reject)
  } else { 
    resolve(x)
  }
}

module.exports = MyPromise